// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// m [author] rhyme_lph
// L [email]  rhymelph@gmail.com
// V [github] https://github.com/rhymelph

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/bill_entity.dart';
import 'package:finance_app/src/entities/business_contact_entity.dart';
import 'package:finance_app/src/entities/credit_note_entity.dart';
import 'package:finance_app/src/entities/debit_note_detail_entity.dart';
import 'package:finance_app/src/entities/ocr_attachment_entity.dart';
import 'package:finance_app/src/http_service/http_debit_note_service.dart';
import 'package:finance_app/src/mixin/form_item_amount_mixin.dart';
import 'package:finance_app/src/mixin/from_attach_mixin.dart';
import 'package:finance_app/src/mixin/init_edit_data_mixin.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/date_time_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/calendar_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:flutter/material.dart';

class NewDebitNoteProvider extends BaseProvider<DebitNoteDetailEntity>
    with FormItemAmountMixin, InitEditDataMixin, FormAttachMixin {
  TextEditingController debitNoteController = TextEditingController();
  FocusNode debitNoteFocusNode = FocusNode();

  TextEditingController billNumberController = TextEditingController();
  FocusNode billNumberFocusNode = FocusNode();

  TextEditingController notesController = TextEditingController();
  FocusNode notesFocusNode = FocusNode();

  BillEntity billNumber;

  BusinessContactEntity issueTo;
  List<String> menuList = [];

  bool isSelectMode = false;

  @override
  void initState() {
    isCredit = false;
    super.initState();
  }

  @override
  int get billInvoiceId => billNumber?.id;

  void unFocus() {
    obtainContext?.call((context) {
      FocusScope.of(context).requestFocus(FocusNode());
    });
  }

  void onChangeIssueDate() {
    unFocus();
    obtainContext?.call((context) async {
      date = await showCalendarBottomSheet(context, date);
      update();
    });
  }

  void onChangeBillNumber() async {
    final result =
        await Routes.navigateTo(RouterGenProviders.billNumberPage, params: {
      'select': billNumber,
      'filterIssueTo': issueTo?.id,
      'isSingleSelect': true,
      'hideClosedBill': false,
    });
    if (result != null) {
      billNumber = result;
      serviceAndProductList.clear();
      availableItems =
          billNumber.items.map((e) => e.toServiceAndProduct()).toList();
      issueTo = billNumber.contact;
      update();
    }
  }

  void onChangeIssueTo() async {
    unFocus();
    final result = await Routes.navigateTo(
        RouterGenProviders.businessContactsPage,
        params: {
          'select': issueTo,
        });
    if (result != null) {
      issueTo = result;
      serviceAndProductList.clear();
      billNumber = null;
      update();
    }
  }

  void onSave() async {
    unFocus();
    if (debitNoteController.text.length == 0) {
      showToast(S.current.please_enter_the_debit_note_number);
      return;
    }

    if (date == null) {
      showToast(S.current.please_select_issue_date);
      return;
    }

    if (issueTo == null) {
      showToast(S.current.please_select_issue_to);
      return;
    }

    if (billNumber == null) {
      showToast(S.current.please_select_bill_number);
      return;
    }

    if (serviceAndProductList.length == 0) {
      showToast(S.current.please_add_item);
      return;
    }

    CreditNoteEntity orderEntity;

    List<int> attachmentIds = await uploadFiles();
    if (attachmentIds == null) return;

    List item = serviceAndProductList
        .map((e) => {
              'type': e.product != null && e.product.id != null
                  ? 'product'
                  : 'service',
              'type_id': e.id,
              'name': e.name,
              'quantity': e.number,
              'price': e.price,
              'is_tax_inclusive': e.isInclusive ? 1 : 0,
              'tax_id': e.tax.id,
              'tax_amount': e.taxAmount,
              'discount_type': e.discountType,
              'discount_value': e.discountValue,
            })
        .toList();

    if (isEdit == true) {
      await post(
          HttpDebitNoteService.updateDebitNote(
            data?.id,
            contact_id: issueTo?.id,
            bill_id: billNumber?.id,
            number: debitNoteController?.text,
            issued_at: DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd'),
            subtotal: subTotal,
            tax_amount: gst,
            total: total,
            notes: notesController?.text,
            attachment_ids: attachmentIds,
            item: item,
          ),
          loadingTip: S.current.loading,
          autoHandler: AutoHandler.Toast, onSuccess: (result) {
        orderEntity = getEntityFromResult<CreditNoteEntity>(result);
      });
    } else {
      await post(
          HttpDebitNoteService.createDebitNote(
            contact_id: issueTo?.id,
            bill_id: billNumber?.id,
            number: debitNoteController?.text,
            issued_at: DateTimeUtils.formatDateTime(date, 'yyyy-MM-dd'),
            subtotal: subTotal,
            tax_amount: gst,
            total: total,
            notes: notesController?.text,
            attachment_ids: attachmentIds,
            item: item,
          ),
          loadingTip: S.current.loading,
          autoHandler: AutoHandler.Toast, onSuccess: (result) {
        orderEntity = getEntityFromResult<CreditNoteEntity>(result);
      });
    }
    if (orderEntity != null) {
      if (isSelectMode == true) {
        obtainContext?.call((context) {
          Navigator.of(context).pop(orderEntity);
        });
      } else {
        id = orderEntity.id;
        await post(editDataFuture,
            loadingTip: S.current.loading,
            autoHandler: AutoHandler.Toast, onSuccess: (result) {
          isEdit = false;
          data = transformData(
              getEntityFromResult<DebitNoteDetailEntity>(result), false);
          update();
        });
      }
    }
  }

  void onSelectMenu(String value) {
    switch (value) {
      case 'Edit':
        onChangeEditMode();
        break;
      case 'Delete':
        onDelete();
        break;
      case 'Receive Refund':
        onReceiveRefund();
        break;
      case 'Keep As Credit':
        onKeepAsCredit();
        break;
      case 'See Payment':
        onSeePayment();
        break;
    }
  }

  void onSeePayment() async {
    await Routes.navigateTo(RouterGenProviders.seePaymentPage, params: {
      'debitId': data.id,
      'isClosed': true,
    });
    loadData();
  }

  void onReceiveRefund() async {
    await Routes.navigateTo(RouterGenProviders.newCashInPage, params: {
      'debitNote': data,
      'isSelectMode': true,
    });
    await post(editDataFuture, onSuccess: (result) {
      isEdit = false;
      data = transformData(
          getEntityFromResult<DebitNoteDetailEntity>(result), false);
      update();
    });
  }

  void onKeepAsCredit() {
    obtainContext?.call((context) async {
      final result = await showKeepDebitCreditInfoBottomSheet(context);
      if (result == true) {
        bool isSuccess = false;
        await post(HttpDebitNoteService.keepCreditNote(data.id),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess) {
          await showDebitKeepAsCreditSuccessTipBottomSheet(context);
          onTry();
        }
      }
    });
  }

  void onDelete() {
    obtainContext?.call((context) async {
      bool isSuccess = await showDeleteDebitNoteInfoBottomSheet(context);
      if (isSuccess == true) {
        isSuccess = false;
        await post(HttpDebitNoteService.deleteDebitNote(data.id),
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        }, autoHandler: AutoHandler.Toast);
        if (isSuccess == true) {
          await showDeleteDebitNoteSuccessBottomSheet(context);
          Navigator.of(context).pop({
            'delete': true,
          });
        }
      }
    });
  }

  @override
  FutureOr<DebitNoteDetailEntity> transformData(
      DebitNoteDetailEntity d, bool isCache) {
    id = d.id;
    debitNoteController.text = d.number;
    date = DateTimeUtils.toDateTime(d.issuedAt);
    issueTo = d.contact;
    billNumber = BillEntity()
      ..id = d.billId
      ..number = d.billNumber;
    // amount = d.invoiceId
    notesController.text = d.notes;
    serviceAndProductList = d.items != null
        ? d.items.map((e) => e.toServiceAndProduct()).toList()
        : [];
    if (d.status == 'closed') {
      menuList = [
        'See Payment',
      ];
    } else {
      menuList = [
        'Edit',
        'Delete',
        'Receive Refund',
        // 'Keep As Credit',
      ];
    }
    handleDataUpdate(d);
    return super.transformData(d, isCache);
  }

  @override
  Future get editDataFuture => HttpDebitNoteService.showDebitNote(id);

  @override
  TextEditingController get numberCtl => debitNoteController;

  @override
  String get type => 'debit_note';

  @override
  List<OcrAttachmentEntity> get attachments => data?.attachments;
}
